﻿#region License

// Another free, open solution by someone who gets it.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Collections.Generic;
using System.IO;

using Args;
using Args.Help;
using Args.Help.Formatters;

using Patterns.Tools.CodeGenerators;
using Patterns.Tools.CodeGenerators.GoogleCode;

namespace Patterns.Tools
{
	/// <summary>
	/// 	Defines the actual entry point to the program.
	/// </summary>
	public static class EntryPoint
	{
		private static readonly IModelBindingDefinition<Options> _model = Configuration.Configure<Options>();

		private static readonly IDictionary<string, Func<Options, CodeGenerationOutput>> _codeGenerators
			= new Dictionary<string, Func<Options, CodeGenerationOutput>>(StringComparer.OrdinalIgnoreCase)
			{
				{ "AssemblyInfo", CreateAssemblyInfo },
				{ "GoogleWiki", Wiki.Generate }
			};

		public static void Run(string[] args)
		{
			try
			{
				if (args == null || args.Length == 0)
				{
					ShowHelp();
					return;
				}

				Options options = _model.CreateAndBind(args);

				if (!string.IsNullOrEmpty(options.WorkingDirectory))
					Environment.CurrentDirectory = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, options.WorkingDirectory));

				if (options.CodeGen) RunCodeGenerator(options);

				// add support for other options here
			}
			catch (Exception ex)
			{
				ConsoleColor defaultColor = Console.ForegroundColor;
				ShowException(ex);
				Console.WriteLine();
				ShowHelp();
				Console.ForegroundColor = defaultColor;
			}
		}

		private static void ShowException(Exception ex)
		{
			Console.ForegroundColor = ConsoleColor.Red;
			Console.WriteLine(ex.Message);
			Console.Write(ex.StackTrace);
			if (ex.InnerException != null)
			{
				Console.Write(@" --> ");
				ShowException(ex.InnerException);
			}
			else Console.WriteLine();
		}

		private static void ShowHelp()
		{
			Console.ForegroundColor = ConsoleColor.Blue;
			var formatter = new ConsoleHelpFormatter(8000, 1, 3);
			formatter.WriteHelp(new HelpProvider().GenerateModelHelp(_model), Console.Out);
		}

		private static void RunCodeGenerator(Options options)
		{
			if (!_codeGenerators.ContainsKey(options.Target)) return;

			CodeGenerationOutput output = _codeGenerators[options.Target](options);

			if (output.IsCodeGenerationHandled || string.IsNullOrEmpty(options.Output) || !Path.HasExtension(options.Output)) return;

			string outputPath = Path.GetFullPath(options.Output);
			var directory = new DirectoryInfo(Path.GetDirectoryName(outputPath));
			if(!directory.Exists) directory.Create();
			File.WriteAllText(outputPath, output.GeneratedCode);
		}

		private static CodeGenerationOutput CreateAssemblyInfo(Options options)
		{
			return new CodeGenerationOutput
			{
				GeneratedCode = new AssemblyInfo
				{
					Product = options.Product,
					Version = options.Version
				}.TransformText()
			};
		}
	}
}